//
// Created by bd on 2019/11/12.
//

#include <iostream>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/keyvalq_struct.h>
#include <event2/buffer.h>
#include <csignal>
#include <cstdlib>

using namespace std;

#define WEBROOT ".."
#define DEFAULT_WEB "index.html"

void http_cb(struct evhttp_request *request, void *arg)
{
    cout << __FUNCTION__ << endl;
    // 1. 获取客户端的请求
    // uri
    string uri = evhttp_request_get_uri(request);
    cout << uri << endl;

    // 请求方法
    string method;
    switch (evhttp_request_get_command(request)) {
        case EVHTTP_REQ_GET:
            method = "GET";
            break;
        case EVHTTP_REQ_POST:
            method = "POST";
            break;
    }
    cout << method << " " << uri << endl;

    // 获取消息报头
    evkeyvalq *headers = evhttp_request_get_input_headers(request);
    for (auto p = headers->tqh_first; p != nullptr; p = p->next.tqe_next) {
        cout << p->key << ": " << p->value << endl;
    }
    // data
    char buf[1024] = {0};
    auto in_buf = evhttp_request_get_input_buffer(request);
    cout << "data: " << endl;
    while (evbuffer_get_length(in_buf)) {
        auto len = evbuffer_remove(in_buf, buf, sizeof(buf) - 1);
        if (len > 0) {
            buf[len] = 0;
            cout << buf << endl;
        }
    }

    // 2. 回复
    // 状态行 消息报头 响应正文


    string html_file = WEBROOT + uri;
    if (uri == "/") {
        html_file += DEFAULT_WEB;
    }

    // 消息报头
    evkeyvalq *out_headers = evhttp_request_get_output_headers(request);
    auto pos = html_file.rfind('.');
    if (pos >= 0) {
        string postfix = html_file.substr(pos + 1, html_file.length() - pos - 1);
        if (postfix == "jpg" || postfix == "gif" || postfix == "png") {
            string type = "image/" + postfix;
            evhttp_add_header(out_headers, "Content-Type", type.c_str());
        } else if (postfix == "zip") {
            evhttp_add_header(out_headers, "Content-Type", "application/zip");
        } else if (postfix == "html") {
            evhttp_add_header(out_headers, "Content-Type", "text/html");
//            evhttp_add_header(out_headers, "Content-Type", "text/html;charset=utf8");
        } else if (postfix == "gz") {
            evhttp_add_header(out_headers, "Content-Type", "application/gzip");
        }
    }

    // 响应正文
    FILE *fp = fopen(html_file.c_str(), "rb");
    if (fp == NULL) {
        evhttp_send_reply(request, HTTP_NOTFOUND, "", nullptr);
        return;
    }

    auto out_buf = evhttp_request_get_output_buffer(request);
    while (true) {
        auto len = fread(buf, 1, sizeof(buf), fp);
        if (len == 0)
            break;
        evbuffer_add(out_buf, buf, len);
    }
    fclose(fp);
    evhttp_send_reply(request, HTTP_OK, "", out_buf);
}

int main()
{
    // 忽略管道信号，发送数据给已关闭的socket
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        return 1;

    auto base = event_base_new();
    if (!base) {
        cerr << "event base new failed, exit." << endl;
        return 1;
    }

    // evhttp
    // 1,创建http上下文
    auto ev = evhttp_new(base);
    if (!ev) {
        cerr << "evhttp new failed." << endl;
        return 1;
    }
    int r = evhttp_bind_socket(ev, "0.0.0.0", 8080);
    if (r != 0) {
        cerr << "http bind 0.0.0.0:8080 failed." << endl;
        return 1;
    }
    cout << "listening http://0.0.0.0:8080" << endl;

    evhttp_set_gencb(ev, http_cb, nullptr);

    event_base_dispatch(base);
    event_base_free(base);
    return 0;
}